/*
 * Copyright 2010 Alessandro Bellucci
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.soupframework.gwt.designerpanel.client;

import java.util.List;

import org.soupframework.gwt.designerpanel.client.designer.DesignerManager;
import org.soupframework.gwt.designerpanel.client.designer.DesignerManagerFactory;
import org.soupframework.gwt.designerpanel.client.designer.OperatingMode;
import org.soupframework.gwt.designerpanel.client.grid.Grid;
import org.soupframework.gwt.designerpanel.client.util.Util;

import com.google.gwt.dom.client.Style.BorderStyle;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Panel;

/**
* DesignerPanel
*/
public class DesignerPanel<T> extends FocusPanel {

	/**
	 * The currently opened context menu
	 */
	private Panel contextMenu;

	/**
	 * The root object to design.
	 */
	private T rootObject;

	/**
	 * The absolute panel for grid, glass panel and designer widget
	 */
	private AbsolutePanel mainPanel;

	/**
	 * The DesignerManager
	 */
	private DesignerManager<T> designerManager;

	/**
	 * Grid
	 */
	private Grid grid;

	/**
	 * Glass panel used to disable interactions with contained objects in DESIGN mode
	 */
	private Element glassPanel;

	/**
	 * Element used to show a marquee
	 */
	private Element marquee;

	public DesignerPanel(T rootObject, DesignerManagerFactory<T> designerManagerFactory){
		super();
		sinkEvents(Event.ONCONTEXTMENU);

		this.rootObject = rootObject;
		this.mainPanel = new AbsolutePanel();
		this.mainPanel.getElement().getStyle().setPosition(Position.ABSOLUTE);
		this.designerManager = designerManagerFactory.createDesignerManager(this);
		this.designerManager.getRootDesigner().getObjectView().getElement().getStyle().setPosition(Position.ABSOLUTE);
		this.mainPanel.add(this.designerManager.getRootDesigner().getObjectView(), 0, 0);
		this.setWidget(this.mainPanel);
	}

	@Override
	public void onBrowserEvent(Event event) {
		if(this.designerManager.getOperatingMode() == OperatingMode.DESIGN_MODE){
			/*if(event.getTypeInt() == Event.ONKEYDOWN){
				int bre=event.getKeyCode();
				System.out.println(bre);
			}*/
			if(event.getTypeInt() == Event.ONKEYDOWN && event.getKeyCode() == KeyCodes.KEY_TAB){
				// TAB was pressed, let the browser handle it, so that focus can go to the next widget.
			}
			else{
				switch(event.getTypeInt()){
					case Event.ONMOUSEDOWN:
						this.setFocus(true);
					case Event.ONMOUSEMOVE:
					case Event.ONMOUSEUP:
					case Event.ONCLICK:
					case Event.ONKEYDOWN:
					case Event.ONKEYPRESS:
					case Event.ONKEYUP:
					case Event.ONCONTEXTMENU:
						event.preventDefault();
						event.stopPropagation();
				}
			}
		}
		super.onBrowserEvent(event);
	}

	public DesignerManager<T> getDesignerManager() {
		return this.designerManager;
	}

	public T getRootObject(){
		return this.rootObject;
	}

	public void enableGlassPanel(){
		if(this.glassPanel == null){
			this.glassPanel = DOM.createDiv();
			DOM.setStyleAttribute(this.glassPanel, "position", "absolute");
			DOM.setStyleAttribute(this.glassPanel, "left", "0");
			DOM.setStyleAttribute(this.glassPanel, "top", "0");
			DOM.setStyleAttribute(this.glassPanel, "backgroundColor", "#000");
			DOM.setStyleAttribute(this.glassPanel, "filter", "alpha(opacity=0)");
			DOM.setStyleAttribute(this.glassPanel, "opacity", "0");
			DOM.setStyleAttribute(this.glassPanel, "zIndex", "999");
		}

		if(!DOM.isOrHasChild(this.mainPanel.getElement(), this.glassPanel)){
			DOM.setStyleAttribute(this.glassPanel, "width", Util.getWidgetStyleWidth(this.mainPanel) + "px");
			DOM.setStyleAttribute(this.glassPanel, "height", Util.getWidgetStyleHeight(this.mainPanel) + "px");
			this.mainPanel.getElement().appendChild(this.glassPanel);
		}
	}

	public void disableGlassPanel(){
		if(this.glassPanel != null && DOM.isOrHasChild(this.mainPanel.getElement(), this.glassPanel)){
			DOM.removeChild(this.mainPanel.getElement(), this.glassPanel);
		}
	}

	public void setCursor(String cursor){
		// ok for live design mode
		//DOM.setStyleAttribute(this.getDesigner().getObjectView().getElement(), "cursor", cursor);
		/// ok for design mode
		DOM.setStyleAttribute(this.getWidget().getElement(), "cursor", cursor);
		if(this.glassPanel != null) {
			DOM.setStyleAttribute(this.glassPanel, "cursor", cursor);
		}
	}

	public void setCursor(Cursor cursor){
		this.setCursor(cursor.getCssName());
		// ok for live design mode
		//this.getDesigner().getObjectView().getElement().getStyle().setCursor(cursor);
		// ok for design mode
		//this.getDesignerManager().getDesignerPanel().getWidget().getElement().getStyle().setCursor(cursor);
	}

	/**
	 * Gets the grid of this DesignerPanel
	 *
	 * @return The grid
	 */
	public Grid getGrid(){
		return this.grid;
	}

	/**
	 * Sets the grid for the DesignerPanel
	 *
	 * @param grid The grid
	 */
	public void setGrid(Grid grid){
		this.grid = grid;
	}

	/**
	 * Shows the grid
	 */
	public void showGrid(){
		if(this.grid != null){
			Element el = this.grid.getElement();
			this.mainPanel.getElement().appendChild(el);
		}
	}

	/**
	 * Hides the grid
	 */
	public void hideGrid(){
		if(this.grid != null){
			if(DOM.isOrHasChild(this.mainPanel.getElement(), this.grid.getElement())){
				this.mainPanel.getElement().removeChild(this.grid.getElement());
			}
		}
	}

	/**
	 * Draws a dashed marquee over at the given coords
	 *
	 * @param startX startX of the marquee
	 * @param startY startY of the marquee
	 * @param endX endX of the marquee
	 * @param endY endY of the marquee
	 */
	public void showMarquee(int startX, int startY, int endX, int endY){
		if(this.marquee == null){
			this.marquee = DOM.createDiv();
			DOM.setStyleAttribute(this.marquee, "position", "absolute");
			this.marquee.getStyle().setBorderStyle(BorderStyle.DOTTED);
			this.marquee.getStyle().setBorderWidth(1, Unit.PX);
			this.marquee.getStyle().setBorderColor("#DDDD00");
			DOM.setStyleAttribute(this.marquee, "zIndex", "998");
		}
		DOM.setStyleAttribute(this.marquee, "left", Math.min(startX, endX) + "px");
		DOM.setStyleAttribute(this.marquee, "top", Math.min(startY, endY) + "px");
		DOM.setStyleAttribute(this.marquee, "width", Math.abs(endX - startX) + "px");
		DOM.setStyleAttribute(this.marquee, "height", Math.abs(endY - startY) + "px");

		if(!DOM.isOrHasChild(this.mainPanel.getElement(), this.marquee)){
			this.mainPanel.getElement().appendChild(this.marquee);
		}
	}

	/**
	 * Hides the marquee
	 */
	public void hideMarquee(){
		if(this.marquee != null && DOM.isOrHasChild(this.mainPanel.getElement(), this.marquee)){
			DOM.removeChild(this.mainPanel.getElement(), this.marquee);
		}
	}

	/**
	 * Show the given context menu Panel for the given objects
	 *
	 * @param widgets the widgets to show the context menu for
	 * @param contextMenu the context menu Panel
	 */
	public void showContextMenu(List<T> objects, Panel contextMenu, int preferredLeft, int preferredTop){
		if(objects != null && objects.size() > 0){
			int top = preferredTop - this.getAbsoluteTop() + Window.getScrollTop(); //Util.getWidgetStyleTop(widgets.get(0));
			int left = preferredLeft - this.getAbsoluteLeft() + Window.getScrollLeft(); //Util.getWidgetStyleLeft(widgets.get(0));
			if(this.contextMenu != null){
				hideContextMenu();
			}
			this.contextMenu = contextMenu;
			this.mainPanel.add(contextMenu, left, top);
		}
	}

	/**
	 * Hides the currently shown context menu
	 */
	public void hideContextMenu(){
		if(this.contextMenu != null){
			this.mainPanel.remove(this.contextMenu);
			this.contextMenu = null;
		}
	}

	@Override
	public void setPixelSize(int width, int height) {
		this.mainPanel.setPixelSize(width, height);
		super.setPixelSize(width, height);
	}

	@Override
	public void setSize(String width, String height) {
		this.mainPanel.setSize(width, height);
		super.setSize(width, height);
	}

	@Override
	public void setWidth(String width) {
		this.mainPanel.setWidth(width);
		super.setWidth(width);
	}

	@Override
	public void setHeight(String height) {
		this.mainPanel.setHeight(height);
		super.setHeight(height);
	}

	public void refresh(){
		this.getDesignerManager().refreshDesigners();
	}
}
